#include <linux/module.h>
#include <linux/netlink.h>
#include <net/sock.h>

#define NETLINK_TEST 25					//定义netlink号
#define STORE_SZ 1024					//存储数据的空间大小

static struct sock *nl_sk = NULL;			//netlink socket
char *storebuf = NULL;					//存储数据指针

//netlink向用户层发送数据
static void netlink_sendto_user(unsigned int dst_pid){
	struct sk_buff *skb = NULL;
	struct nlmsghdr *nlh = NULL;
	int res;

	if(!storebuf)
		return;
	skb = nlmsg_new(strlen(storebuf), 0);		//分配一个sk_buff
	if(!skb)
		printk("failed to new skb");
	nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, strlen(storebuf), 0);
	NETLINK_CB(skb).dst_group = 0;			//设置单播发送
	memcpy(NLMSG_DATA(nlh), storebuf, strlen(storebuf));
	printk("kernel netlink send: %s\n", storebuf);	

	res = netlink_unicast(nl_sk, skb, dst_pid, MSG_DONTWAIT);	//发送数据
	if(res < 0)
		printk("netlink_unicast failed. res=%d \n", res);

}

//内核接收数据的回调函数
void nl_data_ready(struct sk_buff *__skb){
	char *str;
	struct nlmsghdr *nlh;
	
	nlh = nlmsg_hdr(__skb);				//从sk_buff中获取netlink header
	str = NLMSG_DATA(nlh);				//获取netlink数据

	if(storebuf){
		kfree(storebuf);
		storebuf = NULL;
	}
	storebuf = kzalloc(STORE_SZ, GFP_KERNEL);	//分配存储空间
	if(!storebuf)
		return;
	memcpy(storebuf, str, strlen(str));
	printk("kernel netlink recv: %s\n", storebuf);

	netlink_sendto_user(nlh->nlmsg_pid);		//发送数据
}

//初始化netlink配置结构，设置接收数据回调函数
static struct netlink_kernel_cfg cfg = {
	.input = nl_data_ready,
};

//模块初始化
static int __init test_nl_init(void){
	nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
	if(!nl_sk){
		printk("netlink_kernel_create failed\n");
		return -1;
	}

	printk("netlink.ko insmod success\n");
	return 0;
}

//模块退出
static void __exit test_nl_exit(void){
	//相关资源释放
	if(nl_sk)
		netlink_kernel_release(nl_sk);

	if(storebuf)
		kfree(storebuf);

	printk("netlink.ko rmmod success\n");
}

module_init(test_nl_init);
module_exit(test_nl_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("NFS");
